package com.minelx.scriptbuilder.parse.parser;

import com.minelx.sequence.CompositeMatcher;
import com.minelx.sequence.IStringScanner;
import com.minelx.sequence.ReturnMatcher;
import com.minelx.scriptbuilder.script.ScriptContext;
import com.minelx.scriptbuilder.script.attribute.function.IFunctionFactory;
import com.minelx.scriptbuilder.script.attribute.value.IAttribute;
import com.minelx.scriptbuilder.script.operation.IOperation;

import java.util.List;

import static com.minelx.sequence.Collector.toList;

public class FunctionDeclareOperationsParser implements ReturnMatcher<IOperation, IStringScanner> {

	private final ScriptContext context;

	private final IAttribute declared;

	private final CompositeMatcher<String, IStringScanner> paramsTokenizer;

	private final IFunctionFactory functionFactory;

	public FunctionDeclareOperationsParser(ScriptContext context, IAttribute declared, IFunctionFactory functionFactory) {
		this.context = context;
		this.declared = declared;
		this.functionFactory = functionFactory;

		paramsTokenizer = new CompositeMatcher<String, IStringScanner>()
				.add(IStringScanner.matchPage())
				.add(IStringScanner.match(","));
	}

	@Override
	public boolean isMatch(IStringScanner scanner) {
		return scanner.exists("function");
	}

	@Override
	public IOperation onMatched(IStringScanner scanner) {
		scanner.pass("function");
		scanner.trim();
		String functionName = scanner.nextPage();

		// params
		scanner.nextChar(); // '('
		List<String> modelParamNames = scanner.sequence(paramsTokenizer).split(",").collect(toList());
		scanner.nextChar(); // ')'

		scanner.nextChar(); // '{'
		IOperation operations = new StatementsParser(context).get(scanner);
		scanner.nextChar(); // '}'
		return () -> declared.set(functionName,
				functionFactory.createFunction(context, modelParamNames, operations));
	}

}
